#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_THREAD (4)

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int* data = NULL;
int numFinish = 0;
int numElement = 100;

#define checkPthreadCode(string, val) {			\
 if (val) {                                     \
   printf("Failed with %d at %s\n", val, string); \
   exit(1);                                     \
 }                                              \
}

void* process(void* param) {
	const int numElementPerThread = ((int*)param)[0];
	const int threadId = ((int*)param)[1];
	int rc;
	
	while(numFinish != numElement) {
		int* ptr = NULL;
	
		rc = pthread_mutex_lock(&mutex);
		checkPthreadCode("pthread_mutex_lock", rc);
		
		ptr = data + numFinish;
		numFinish += numElementPerThread;
		
		rc = pthread_mutex_unlock(&mutex);
		checkPthreadCode("pthread_mutex_unlock", rc);
		
		printf("thread %d: processing elements in [%d, %d]\n", 
			threadId, ptr[0], ptr[numElementPerThread - 1]);
	}
	

	
	return NULL;
}

int main() {
	const int numElementPerThread = 10;
	data = (int*)malloc(sizeof(int)*numElement);
	for(int i = 0; i < numElement; i++) {
		data[i] = i;
	}
	pthread_t thread[NUM_THREAD];
	int param[NUM_THREAD][2];
	
	for(int i = 0; i < NUM_THREAD; i++) {
		param[i][0] = numElementPerThread;
		param[i][1] = i;
	}
	int rc = 0;

	for(int i = 0; i < NUM_THREAD; i++) {
		rc = pthread_create(&(thread[i]), NULL, process, param[i]);
		checkPthreadCode("pthread_create", rc);
	}
	
	printf("Wait for the threads to complete, and release their resources\n");
	for (int i=0; i < NUM_THREAD; ++i) {
		rc = pthread_join(thread[i], NULL);
		checkPthreadCode("pthread_join", rc);
	}
 
	rc = pthread_mutex_destroy(&mutex);
	
	return EXIT_SUCCESS;
}
